﻿using System;
using Microsoft.Extensions.Caching.Memory;

namespace OS.Common.Plugs.CachePlug
{
    /// <summary>
    /// 默认缓存插件
    /// </summary>
    public class DefaultCachePlug : ICachePlug
    {
        private static readonly MemoryCache MCache = new MemoryCache(new MemoryCacheOptions());

        /// <summary>
        /// 添加缓存，如果存在则更新
        /// </summary>
        /// <typeparam name="T">添加缓存对象类型</typeparam>
        /// <param name="key">添加对象的key</param>
        /// <param name="obj">值</param>
        /// <param name="slidingExpiration">相对过期的TimeSpan  如果使用固定时间  =TimeSpan.Zero</param>
        /// <param name="absoluteExpiration">绝对过期时间,不为空则按照绝对过期时间计算</param>
        /// <returns>是否添加成功</returns>
        [Obsolete]
        public virtual bool AddOrUpdate<T>(string key, T obj, TimeSpan slidingExpiration, DateTime? absoluteExpiration = default(DateTime?))
        {
            return Add(key, obj, slidingExpiration, absoluteExpiration);
        }

        /// <summary>
        /// 添加时间段过期缓存，如果存在则更新
        /// </summary>
        /// <typeparam name="T">添加缓存对象类型</typeparam>
        /// <param name="key">添加对象的key</param>
        /// <param name="obj">值</param>
        /// <param name="slidingExpiration">相对过期的TimeSpan</param>
        /// <returns>是否添加成功</returns>
        public virtual bool Set<T>(string key, T obj, TimeSpan slidingExpiration)
        {
            return Add(key, obj, slidingExpiration, null);
        }

        /// <summary>
        /// 添加固定过期时间缓存,如果存在则更新
        /// </summary>
        /// <typeparam name="T">添加缓存对象类型</typeparam>
        /// <param name="key">添加对象的key</param>
        /// <param name="obj">值</param>
        /// <param name="absoluteExpiration">绝对过期时间,不为空则按照绝对过期时间计算</param>
        /// <returns>是否添加成功</returns>
        public virtual bool Set<T>(string key, T obj, DateTime absoluteExpiration)
        {
            return Add(key, obj, TimeSpan.Zero, absoluteExpiration);
        }

        /// <summary>
        /// 添加缓存，如果存在则更新
        /// </summary>
        /// <typeparam name="T">添加缓存对象类型</typeparam>
        /// <param name="key">添加对象的key</param>
        /// <param name="obj">值</param>
        /// <param name="slidingExpiration">相对过期的TimeSpan</param>
        /// <param name="absoluteExpiration">绝对过期时间,不为空则按照绝对过期时间计算</param>
        /// <returns></returns>
        private static bool Add<T>(string key, T obj, TimeSpan slidingExpiration, DateTime? absoluteExpiration)
        {
            if (slidingExpiration == TimeSpan.Zero && !absoluteExpiration.HasValue)
                throw new ArgumentNullException("slidingExpiration", "缓存过期时间不正确,需要设置固定过期时间或者相对过期时间");

            MemoryCacheEntryOptions memoryCacheEntryOptions = new MemoryCacheEntryOptions();
            if (absoluteExpiration.HasValue)
                memoryCacheEntryOptions.AbsoluteExpiration = new DateTimeOffset(absoluteExpiration.Value);
            else
                memoryCacheEntryOptions.SlidingExpiration = slidingExpiration;

            MCache.Set(key, obj, memoryCacheEntryOptions);
            return true;
        }

        /// <summary>
        /// 获取缓存对象
        /// </summary>
        /// <typeparam name="T">获取缓存对象类型</typeparam>
        /// <param name="key">key</param>
        /// <returns>获取指定key对应的值</returns>
        public virtual T Get<T>(string key)
        {
            return MCache.Get<T>(key);
        }

        /// <summary>
        /// 移除缓存对象
        /// </summary>
        /// <param name="key">key</param>
        /// <returns>是否成功</returns>
        public virtual bool Remove(string key)
        {
            MCache.Remove(key);
            return true;
        }
    }
}